package com.cardone.platform.configuration.service;

import java.util.List;
import java.util.Map;
import java.util.UUID;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.Setter;

import org.apache.commons.lang3.ArrayUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.transaction.annotation.Transactional;

import com.cardone.common.dto.PaginationDto;
import com.cardone.common.utils.EntityUtils;
import com.cardone.persistent.CommonDtoAttributes;
import com.cardone.platform.configuration.dao.DictionaryDao;
import com.cardone.platform.configuration.dao.DictionaryTypeDao;
import com.cardone.platform.configuration.dto.DictionaryDto;
import com.cardone.platform.configuration.dto.DictionaryTypeDto;

/**
 * 字典服务
 * 
 * @author yaoht
 * 
 */
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class DictionaryDefaultService implements DictionaryService {
	/**
	 * 字典数据持久
	 */
	private DictionaryDao dictionaryDao;

	/**
	 * 字典类型数据持久
	 */
	private DictionaryTypeDao dictionaryTypeDao;

	@Override
	@Transactional
	@CacheEvict(value = DictionaryService.BEAN_ID, allEntries = true)
	public int deleteDictionaryByCode(@NonNull DictionaryDto deleteDictionary) {
		return this.dictionaryDao.deleteByCode(deleteDictionary, new String[] {});
	}

	@Override
	@Transactional
	@CacheEvict(value = DictionaryService.BEAN_ID, allEntries = true)
	public int deleteDictionaryByIds(@NonNull DictionaryDto deleteDictionary) {
		return this.dictionaryDao.deleteByIds(deleteDictionary);
	}

	@Override
	@Transactional
	@CacheEvict(value = DictionaryService.BEAN_ID, allEntries = true)
	public int deleteDictionaryTypeByCode(@NonNull DictionaryTypeDto deleteDictionaryType) {
		return this.dictionaryTypeDao.deleteByCode(deleteDictionaryType, new String[] {});
	}

	@Override
	@Transactional
	@CacheEvict(value = DictionaryService.BEAN_ID, allEntries = true)
	public int deleteDictionaryTypeByIds(@NonNull DictionaryTypeDto deleteDictionaryType) {
		return this.dictionaryTypeDao.deleteByIds(deleteDictionaryType);
	}

	@Override
	@Cacheable(value = DictionaryService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public DictionaryDto findDictionaryByCode(@NonNull DictionaryDto findDictionary) {
		return this.dictionaryDao.findByCode(DictionaryDto.class, findDictionary, null, CommonDtoAttributes.id.name());
	}

	@Override
	@Cacheable(value = DictionaryService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public DictionaryDto findDictionaryById(@NonNull DictionaryDto findDictionary) {
		return this.dictionaryDao.findByCode(DictionaryDto.class, findDictionary, null, CommonDtoAttributes.id.name());
	}

	@Override
	@Cacheable(value = DictionaryService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public DictionaryTypeDto findDictionaryTypeByCode(@NonNull DictionaryTypeDto findDictionaryType) {
		return this.dictionaryTypeDao.findByCode(DictionaryTypeDto.class, findDictionaryType, null, CommonDtoAttributes.id.name());
	}

	@Override
	@Cacheable(value = DictionaryService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public DictionaryTypeDto findDictionaryTypeById(@NonNull DictionaryTypeDto findDictionaryType) {
		return this.dictionaryTypeDao.findByCode(DictionaryTypeDto.class, findDictionaryType, null, CommonDtoAttributes.id.name());
	}

	@Override
	@Cacheable(value = DictionaryService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public List<DictionaryDto> findListDictionaryByCode(@NonNull DictionaryDto findListDictionary) {
		return this.dictionaryDao.findListByCode(DictionaryDto.class, findListDictionary, new String[] {}, new String[] {});
	}

	@Override
	@Cacheable(value = DictionaryService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public List<DictionaryDto> findListDictionaryByName(@NonNull DictionaryDto findListDictionary) {
		return this.dictionaryDao.findListByName(DictionaryDto.class, findListDictionary);
	}

	@Override
	@Cacheable(value = DictionaryService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public List<DictionaryTypeDto> findListDictionaryTypeByCode(@NonNull DictionaryTypeDto findListDictionaryType) {
		return this.dictionaryTypeDao.findListByCode(DictionaryTypeDto.class, findListDictionaryType, new String[] {}, new String[] {});
	}

	@Override
	@Cacheable(value = DictionaryService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public List<DictionaryTypeDto> findListDictionaryTypeByName(@NonNull DictionaryTypeDto findListDictionaryType) {
		return this.dictionaryTypeDao.findListByName(DictionaryTypeDto.class, findListDictionaryType);
	}

	@Override
	@Cacheable(value = DictionaryService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public PaginationDto<DictionaryDto> paginationDictionaryByCode(@NonNull DictionaryDto paginationDictionary) {
		return this.dictionaryDao.paginationByCode(DictionaryDto.class, paginationDictionary);
	}

	@Override
	@Cacheable(value = DictionaryService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public PaginationDto<Map<String, Object>> paginationDictionaryByName(@NonNull DictionaryDto paginationDictionary) {
		return this.dictionaryDao.paginationByName(paginationDictionary);
	}

	@Override
	@Cacheable(value = DictionaryService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public PaginationDto<DictionaryTypeDto> paginationDictionaryTypeByCode(@NonNull DictionaryTypeDto paginationDictionaryType) {
		return this.dictionaryTypeDao.paginationByCode(DictionaryTypeDto.class, paginationDictionaryType);
	}

	@Override
	@Cacheable(value = DictionaryService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public PaginationDto<Map<String, Object>> paginationDictionaryTypeByName(@NonNull DictionaryTypeDto paginationDictionaryType) {
		return this.dictionaryTypeDao.paginationByName(paginationDictionaryType);
	}

	@Override
	@Cacheable(value = DictionaryService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public Integer readDictionaryByCodeNqId(@NonNull DictionaryDto readDictionary) {
		return this.dictionaryDao.readByCodeNqId(Integer.class, readDictionary);
	}

	@Override
	@Cacheable(value = DictionaryService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public Integer readDictionaryByName(@NonNull DictionaryDto readDictionary) {
		return this.dictionaryDao.readByName(Integer.class, null, readDictionary);
	}

	@Override
	@Cacheable(value = DictionaryService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public Integer readDictionaryTypeByCodeNqId(@NonNull DictionaryTypeDto readDictionaryType) {
		return this.dictionaryTypeDao.readByCodeNqId(Integer.class, readDictionaryType);
	}

	@Override
	@Cacheable(value = DictionaryService.BEAN_ID, key = com.cardone.common.cache.Constants.KEY_1)
	public Integer readDictionaryTypeByName(@NonNull DictionaryTypeDto readDictionaryType) {
		return this.dictionaryTypeDao.readByName(Integer.class, null, readDictionaryType);
	}

	@Override
	@CacheEvict(value = DictionaryService.BEAN_ID, allEntries = true)
	public void reload() {
		this.dictionaryDao.reload();

		this.dictionaryTypeDao.reload();
	}

	@Override
	@Transactional
	@CacheEvict(value = DictionaryService.BEAN_ID, allEntries = true)
	public DictionaryDto saveDictionaryByIdOrCode(@NonNull DictionaryDto saveDictionary) {
		final String[] whereAndEqProperties = EntityUtils.getWhereProperties(saveDictionary, CommonDtoAttributes.code.name());

		final DictionaryDto oldDictionary = this.dictionaryDao.findByCode(DictionaryDto.class, saveDictionary, null,
		        whereAndEqProperties);

		if (oldDictionary == null) {
			saveDictionary.setId(UUID.randomUUID().toString());

			this.dictionaryDao.insertByCode(saveDictionary);

			final String[] notNullIdProperties = EntityUtils.getNotNullIdProperties(saveDictionary);

			return this.dictionaryDao.findByCode(DictionaryDto.class, saveDictionary, null, notNullIdProperties);
		}

		final String[] useProperties = EntityUtils.addNotNullTimeSegmentProperties(new String[] { CommonDtoAttributes.parentId.name(),
		        CommonDtoAttributes.typeId.name(), CommonDtoAttributes.code.name(), CommonDtoAttributes.name.name(),
		        CommonDtoAttributes.orderCode.name(), CommonDtoAttributes.value.name(), CommonDtoAttributes.remark.name() },
		        saveDictionary);

		final String[] updateProperties = com.cardone.common.utils.BeanUtils.diffProperties(saveDictionary, oldDictionary,
		        useProperties);

		if (ArrayUtils.isEmpty(updateProperties)) {
			return oldDictionary;
		}

		final String[] notNullIdProperties = EntityUtils.getNotNullIdProperties(oldDictionary);

		com.cardone.common.utils.BeanUtils.copyProperties(oldDictionary, saveDictionary, notNullIdProperties);

		this.dictionaryDao.updateByCode(saveDictionary, updateProperties, notNullIdProperties);

		return this.dictionaryDao.findByCode(DictionaryDto.class, oldDictionary, null, notNullIdProperties);
	}

	@Override
	@Transactional
	@CacheEvict(value = DictionaryService.BEAN_ID, allEntries = true)
	public DictionaryDto saveDictionaryByName(@NonNull DictionaryDto saveDictionary) {
		final String[] whereAndEqProperties = EntityUtils.getWhereProperties(saveDictionary, CommonDtoAttributes.code.name());

		final DictionaryDto oldDictionary = this.dictionaryDao.findByCode(DictionaryDto.class, saveDictionary, null,
		        whereAndEqProperties);

		if (oldDictionary == null) {
			saveDictionary.setId(UUID.randomUUID().toString());

			this.dictionaryDao.insertByCode(saveDictionary);

			final String[] notNullIdProperties = EntityUtils.getNotNullIdProperties(saveDictionary);

			return this.dictionaryDao.findByCode(DictionaryDto.class, saveDictionary, null, notNullIdProperties);
		}

		final String[] useProperties = EntityUtils.addNotNullTimeSegmentProperties(new String[] { CommonDtoAttributes.parentId.name(),
		        CommonDtoAttributes.typeId.name(), CommonDtoAttributes.code.name(), CommonDtoAttributes.name.name(),
		        CommonDtoAttributes.orderCode.name(), CommonDtoAttributes.value.name(), CommonDtoAttributes.remark.name() },
		        saveDictionary);

		final String[] updateProperties = com.cardone.common.utils.BeanUtils.diffProperties(saveDictionary, oldDictionary,
		        useProperties);

		if (ArrayUtils.isEmpty(updateProperties)) {
			return oldDictionary;
		}

		final String[] notNullIdProperties = EntityUtils.getNotNullIdProperties(oldDictionary);

		com.cardone.common.utils.BeanUtils.copyProperties(oldDictionary, saveDictionary, notNullIdProperties);

		this.dictionaryDao.updateByCode(saveDictionary, updateProperties, notNullIdProperties);

		return this.dictionaryDao.findByCode(DictionaryDto.class, oldDictionary, null, notNullIdProperties);
	}

	@Override
	@Transactional
	@CacheEvict(value = DictionaryService.BEAN_ID, allEntries = true)
	public DictionaryTypeDto saveDictionaryTypeByIdOrCode(@NonNull DictionaryTypeDto saveDictionaryType) {
		final String[] whereAndEqProperties = EntityUtils.getWhereProperties(saveDictionaryType, CommonDtoAttributes.code.name());

		final DictionaryTypeDto oldDictionaryType = this.dictionaryTypeDao.findByCode(DictionaryTypeDto.class, saveDictionaryType,
		        null, whereAndEqProperties);

		if (oldDictionaryType == null) {
			saveDictionaryType.setId(UUID.randomUUID().toString());

			this.dictionaryTypeDao.insertByCode(saveDictionaryType);

			final String[] notNullIdProperties = EntityUtils.getNotNullIdProperties(saveDictionaryType);

			return this.dictionaryTypeDao.findByCode(DictionaryTypeDto.class, saveDictionaryType, null, notNullIdProperties);
		}

		final String[] useProperties = EntityUtils.addNotNullTimeSegmentProperties(new String[] { CommonDtoAttributes.parentId.name(),
		        CommonDtoAttributes.typeId.name(), CommonDtoAttributes.code.name(), CommonDtoAttributes.name.name(),
		        CommonDtoAttributes.orderCode.name(), CommonDtoAttributes.value.name(), CommonDtoAttributes.remark.name() },
		        saveDictionaryType);

		final String[] updateProperties = com.cardone.common.utils.BeanUtils.diffProperties(saveDictionaryType, oldDictionaryType,
		        useProperties);

		if (ArrayUtils.isEmpty(updateProperties)) {
			return oldDictionaryType;
		}

		final String[] notNullIdProperties = EntityUtils.getNotNullIdProperties(oldDictionaryType);

		com.cardone.common.utils.BeanUtils.copyProperties(oldDictionaryType, saveDictionaryType, notNullIdProperties);

		this.dictionaryTypeDao.updateByCode(saveDictionaryType, updateProperties, notNullIdProperties);

		return this.dictionaryTypeDao.findByCode(DictionaryTypeDto.class, oldDictionaryType, null, notNullIdProperties);
	}

	@Override
	@Transactional
	@CacheEvict(value = DictionaryService.BEAN_ID, allEntries = true)
	public DictionaryTypeDto saveDictionaryTypeByName(@NonNull DictionaryTypeDto saveDictionaryType) {
		final String[] whereAndEqProperties = EntityUtils.getWhereProperties(saveDictionaryType, CommonDtoAttributes.code.name());

		final DictionaryTypeDto oldDictionaryType = this.dictionaryTypeDao.findByCode(DictionaryTypeDto.class, saveDictionaryType,
		        null, whereAndEqProperties);

		if (oldDictionaryType == null) {
			saveDictionaryType.setId(UUID.randomUUID().toString());

			this.dictionaryTypeDao.insertByCode(saveDictionaryType);

			final String[] notNullIdProperties = EntityUtils.getNotNullIdProperties(saveDictionaryType);

			return this.dictionaryTypeDao.findByCode(DictionaryTypeDto.class, saveDictionaryType, null, notNullIdProperties);
		}

		final String[] useProperties = EntityUtils.addNotNullTimeSegmentProperties(new String[] { CommonDtoAttributes.parentId.name(),
		        CommonDtoAttributes.typeId.name(), CommonDtoAttributes.code.name(), CommonDtoAttributes.name.name(),
		        CommonDtoAttributes.orderCode.name(), CommonDtoAttributes.value.name(), CommonDtoAttributes.remark.name() },
		        saveDictionaryType);

		final String[] updateProperties = com.cardone.common.utils.BeanUtils.diffProperties(saveDictionaryType, oldDictionaryType,
		        useProperties);

		if (ArrayUtils.isEmpty(updateProperties)) {
			return oldDictionaryType;
		}

		final String[] notNullIdProperties = EntityUtils.getNotNullIdProperties(oldDictionaryType);

		com.cardone.common.utils.BeanUtils.copyProperties(oldDictionaryType, saveDictionaryType, notNullIdProperties);

		this.dictionaryTypeDao.updateByCode(saveDictionaryType, updateProperties, notNullIdProperties);

		return this.dictionaryTypeDao.findByCode(DictionaryTypeDto.class, oldDictionaryType, null, notNullIdProperties);
	}

	@Override
	@Transactional
	@CacheEvict(value = DictionaryService.BEAN_ID, allEntries = true)
	public int updateDictionaryByCode(@NonNull DictionaryDto updateDictionary) {
		return this.dictionaryDao.updateByCode(updateDictionary, new String[] {}, new String[] {});
	}

	@Override
	@Transactional
	@CacheEvict(value = DictionaryService.BEAN_ID, allEntries = true)
	public int updateDictionaryByIds(@NonNull DictionaryDto updateDictionary) {
		return this.dictionaryDao.updateByIds(updateDictionary);
	}

	@Override
	@Transactional
	@CacheEvict(value = DictionaryService.BEAN_ID, allEntries = true)
	public int updateDictionaryTypeByCode(@NonNull DictionaryTypeDto updateDictionaryType) {
		return this.dictionaryTypeDao.updateByCode(updateDictionaryType, new String[] {}, new String[] {});
	}

	@Override
	@Transactional
	@CacheEvict(value = DictionaryService.BEAN_ID, allEntries = true)
	public int updateDictionaryTypeByIds(@NonNull DictionaryTypeDto updateDictionaryType) {
		return this.dictionaryTypeDao.updateByIds(updateDictionaryType);
	}
}